<?php
/**
 * @author		João Batista Neto
 * @brief		Implementação de uma conexão HTTP que utiliza cURL
 * @package		rpo.http.curl
 */

require_once 'rpo/http/HTTPConnection.php';
require_once 'rpo/base/Object.php';

/**
 * @brief		Conexão HTTP com cURL
 * @details		Implementação de uma requisição HTTP que utiliza cURL
 * @class		CURLConnection
 */
class CURLConnection extends Object implements HTTPConnection {
	/**
	 * @brief	Recurso cURL
	 * @var		resource
	 */
	private $resource;

	/**
	 * @brief	Constroi o objeto de conexão HTTP que utiliza cURL
	 * @throws	RuntimeException Se cURL não estiver disponível
	 */
	public function __construct(){
		if ( !function_exists( 'curl_init' ) ){
			throw new RuntimeException( 'cURL não está disponível.' );
		}
	}

	/**
	 * @brief	Destroi o objeto e fecha a conexão
	 */
	public function __destruct(){
		if ( is_resource( $this->resource ) ){
			curl_close( $this->resource );
		}
	}

	/**
	 * @brief		Fecha a conexão
	 * @return		HTTPConnection
	 * @throws		BadMethodCallException Se a conexão não tiver sido aberta
	 */
	public function close() {
		if ( is_resource( $this->resource ) ){
			curl_close( $this->resource );
		} else {
			throw new BadMethodCallException( 'A conexão não foi aberta' );
		}
	}

	/**
	 * @brief		Abre a conexão
	 * @return		HTTPConnection
	 * @throws		RuntimeException Se cURL não estiver disponível ou se não for possível iniciá-la
	 */
	public function open() {
		$resource = curl_init();

		if ( is_resource( $resource ) ){
			$this->resource =& $resource;
		} else {
			throw new RuntimeException( 'Não foi possível iniciar a cURL.' );
		}

		return $this;
	}

	/**
	 * @brief		Requisição HTTP
	 * @details		Envia uma requisição HTTP contendo uma lista de cabeçalhos e, opcionalmente
	 * um corpo.
	 * @param		$request HTTPRequest Requisição que será enviada ao servidor
	 * @return		HTTPResponse
	 */
	public function request( HTTPRequest $request ){
		$requestURI = $request->getURI();
		$requestBody = $request->getBody();
		$requestMethod = $request->getMethod();

		if ( !is_null( $requestBody ) ){
			$bodyFields = $requestBody->httpBuildQuery();
		}

		$headers = array();

		foreach ( $request->getHeaderIterator() as $headerField ){
			$headers[] = (string) $headerField;
		}

		curl_setopt( $this->resource , CURLOPT_RETURNTRANSFER , 1 );
		curl_setopt( $this->resource , CURLOPT_HTTPHEADER , $headers );

		switch ( $requestMethod ){
			case HTTPRequestMethod::POST:
			case HTTPRequestMethod::PUT:
				curl_setopt( $this->resource , CURLOPT_POSTFIELDS , $bodyFields );
				break;
			default:
				$requestURI .= sprintf( '?%s' , $bodyFields );
		}

		curl_setopt( $this->resource , CURLOPT_CUSTOMREQUEST , $requestMethod );
		curl_setopt( $this->resource , CURLOPT_URL , $requestURI );

		$response = curl_exec( $this->resource );
		$error = curl_error( $this->resource );
		$errno = curl_errno( $this->resource );

		if ( $errno !== 0 ){
			throw new RuntimeException( $error , $errno );
		}

		return $response;
	}
}